﻿Imports System.ComponentModel
Namespace GestionCalculs

    ''' <summary>
    ''' La classe fonctionCalcul a un mode de recalcul (sur ordre ou automatique)
    ''' Elle possède un délégué qu'elle exécute à chaque fois que l'état devient à MAJ (si le mode de recalcul est automatique)
    ''' Cette classe sert à déléguer la gestion des recalculs d'une fonction (ie moteur méthode 2)
    ''' dans ce cas, elle possède une référence à cette classe, cette dernière interceptant les évènements générateur d'un changement d'état
    ''' </summary>
    ''' <remarks></remarks>
    Public MustInherit Class FonctionCalcul
        Implements IFonctionCalcul


#Region "Déclarations globales"
        ''' <summary>
        ''' Encapsule une méthode permettant de déterminer le type de <see cref="FonctionCalcul" />
        ''' </summary>
        ''' <remarks></remarks>
        Public Delegate Sub TypeFonctionCalcul()

        ''' <summary>
        ''' 
        ''' </summary>
        ''' <remarks></remarks>
        Protected _modeRecalcul As TypeRecalcul

        ''' <summary>
        ''' 
        ''' </summary>
        ''' <remarks></remarks>
        Protected _etatCalcul As EtatCalcul

        ''' <summary>
        ''' 
        ''' </summary>
        ''' <remarks></remarks>
        Protected _description As String

        ''' <summary>
        ''' 
        ''' </summary>
        ''' <remarks></remarks>
        Protected _tempsCalcul As System.TimeSpan
#End Region
#Region "Constructeur"

        ''' <summary>
        ''' 
        ''' </summary>
        ''' <param name="modeRecalcul"></param>
        ''' <param name="etatCalcul"></param>
        ''' <remarks></remarks>
        Public Sub New(ByVal modeRecalcul As TypeRecalcul, Optional ByVal etatCalcul As EtatCalcul = Nothing)

            If Not etatCalcul Is Nothing Then _etatCalcul = etatCalcul Else _etatCalcul = New EtatCalcul
            _modeRecalcul = modeRecalcul
            _etatCalcul.Value = ValueEtatCalcul.A_MAJ
            AddHandler _etatCalcul.ValueChanged, AddressOf onEtatCalculValueChanged
        End Sub
#End Region
#Region "Propriétés"
        ''' <summary>
        ''' Etat du calcul de la fonction de calcul (à jour / à mettre à jour / non initialisé)
        ''' </summary>
        ''' <remarks></remarks>
        Public ReadOnly Property EtatCalcul() As ValueEtatCalcul Implements IFonctionCalcul.EtatCalcul
            Get
                Return _etatCalcul.Value
            End Get
        End Property

        ''' <summary>
        ''' Temps de calcul estimé de la fonction de calcul
        ''' </summary>
        ''' <remarks></remarks>
        Public ReadOnly Property TempsCalcul() As System.TimeSpan Implements IFonctionCalcul.TempsCalcul
            Get
                Return _tempsCalcul
            End Get
        End Property

        ''' <summary>
        ''' Mode de recalcul de la fonction de calcul
        ''' </summary>
        ''' <remarks></remarks>
        Public Overridable Property ModeRecalcul() As TypeRecalcul Implements IFonctionCalcul.ModeRecalcul
            Get
                Return _modeRecalcul
            End Get
            Set(ByVal value As TypeRecalcul)
                If value <> _modeRecalcul Then
                    If value = TypeRecalcul.Automatique And EtatCalcul = ValueEtatCalcul.A_MAJ Then Calculer()
                    _modeRecalcul = value
                    RaiseEventModeRecalculChanged(Me, New EventArgs)
                End If
            End Set
        End Property

        ''' <summary>
        ''' 
        ''' </summary>
        ''' <remarks></remarks>
        Public Property Description() As String Implements IFonctionCalcul.Description
            Get
                Return _description
            End Get
            Set(ByVal value As String)
                _description = value
            End Set
        End Property
#End Region
#Region "Méthodes de Calcul / Invalidation"
        ''' <summary>
        ''' 
        ''' </summary>
        ''' <remarks></remarks>
        Public MustOverride Sub Calculer(Optional ByVal ForcerCalcul As Boolean = False) Implements IFonctionCalcul.Calculer
        ''' <summary>
        ''' 
        ''' </summary>
        ''' <remarks></remarks>
        Public Overridable Sub Invalider() Implements IFonctionCalcul.Invalider
            If EtatCalcul <> ValueEtatCalcul.NON_INITIALISE Then
                RaiseEventBeforeInvalider(Me, New EventArgs)
                If ModeRecalcul = TypeRecalcul.Automatique Then
                    Calculer()
                ElseIf ModeRecalcul = TypeRecalcul.SurOrdre Then
                    _etatCalcul.Value = ValueEtatCalcul.A_MAJ
                End If
                RaiseEventAfterInvalider(Me, New EventArgs)
            End If
        End Sub
#End Region
#Region "Méthodes de gestion de la calculabilité"
        ''' <summary>
        ''' 
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub EstCalculable() Implements IFonctionCalcul.EstCalculable
            If EtatCalcul = ValueEtatCalcul.NON_INITIALISE Then
                If _modeRecalcul = TypeRecalcul.Automatique Then
                    'La fonction Calculer fait changer d'état la variable _EtatCalcul et ce changement
                    'est récupéré dans la procédure actualise
                    Calculer()
                Else
                    _etatCalcul.Value = ValueEtatCalcul.A_MAJ
                End If
            End If
        End Sub
        ''' <summary>
        ''' 
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub EstNonCalculable() Implements IFonctionCalcul.EstNonCalculable
            If _etatCalcul.Value <> ValueEtatCalcul.NON_INITIALISE Then
                'Le changement d'état est récupéré dans la fonction actualise et une notification est alors
                'envoyée aux observateurs
                _etatCalcul.Value = ValueEtatCalcul.NON_INITIALISE
            End If
        End Sub
#End Region
#Region "Interception des évènements extérieurs"
        Private Sub onEtatCalculValueChanged(ByVal sender As Object, ByVal e As EventArgs)
            RaiseEventEtatCalculChanged(Me, e)
        End Sub
#End Region
#Region "Evènements générés"
        Public Event EtatCalculChanged As EventHandler Implements IFonctionCalcul.EtatCalculChanged
        Protected Sub RaiseEventEtatCalculChanged(ByVal sender As Object, ByVal e As EventArgs)
            RaiseEvent EtatCalculChanged(sender, e)
        End Sub
        Public Event ModeRecalculChanged As EventHandler Implements IFonctionCalcul.ModeRecalculChanged
        Protected Sub RaiseEventModeRecalculChanged(ByVal sender As Object, ByVal e As EventArgs)
            RaiseEvent ModeRecalculChanged(sender, e)
        End Sub
        Public Event BeforeInvalider As EventHandler Implements IFonctionCalcul.BeforeInvalider
        Protected Sub RaiseEventBeforeInvalider(ByVal sender As Object, ByVal e As EventArgs)
            RaiseEvent BeforeInvalider(sender, e)
        End Sub
        Public Event AfterInvalider As EventHandler Implements IFonctionCalcul.AfterInvalider
        Protected Sub RaiseEventAfterInvalider(ByVal sender As Object, ByVal e As EventArgs)
            RaiseEvent AfterInvalider(sender, e)
        End Sub
        Public Event AfterCalculer As EventHandler Implements IFonctionCalcul.AfterCalculer
        Protected Sub RaiseEventAfterCalculer(ByVal sender As Object, ByVal e As EventArgs)
            RaiseEvent AfterCalculer(sender, e)
        End Sub
#End Region


#Region "INotifyPropertyChanged"
        ''' <summary>
        ''' 
        ''' </summary>
        ''' <param name="info"></param>
        ''' <remarks></remarks>
        Protected Sub NotifyPropertyChanged(ByVal info As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
        End Sub
        Public Event PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
#End Region

    End Class

End Namespace
